package ca.compsci.opent.interpreter;

import java.io.*;

import ca.compsci.opent.compiler.Utils;
import ca.compsci.opent.compiler.codegen.BytecodeGenerator;
import ca.compsci.opent.compiler.lexer.Lexer;
import ca.compsci.opent.compiler.lexer.LexerException;
import ca.compsci.opent.compiler.node.Start;
import ca.compsci.opent.compiler.optimizer.PostSemanticOptimizer;
import ca.compsci.opent.compiler.parser.Parser;
import ca.compsci.opent.compiler.parser.ParserException;
import ca.compsci.opent.compiler.semantics.*;

public class Main {
	
	public static void main(final String[] args) throws Exception {
		if (args.length == 0) {
			System.err.println("No file specified!");
			System.exit(1);
		}
		File file = new File(args[0]);
		FileReader file_reader = new FileReader(file);
		
		try {
			Lexer lexer = new Lexer(new PushbackReader(new BufferedReader(file_reader)));
			Parser parser = new Parser(lexer);
			
			Start ast = parser.parse();
			SemanticAnalyzer analyzer = new SemanticAnalyzer(file.getName());
			ast.apply(analyzer);
			
			SymbolTable table = analyzer.getTable();
			
			ast.apply(new PostSemanticOptimizer(table));
			
			BytecodeGenerator generator = new BytecodeGenerator(file.getParentFile(), table);
			ast.apply(generator);
			
			final byte[] bytecode = generator.getBytecode();
			
			final ClassLoader loader = new ClassLoader(ClassLoader.getSystemClassLoader()) {
				@Override
				protected Class<?> findClass(String name) throws ClassNotFoundException {
					if (name.equals(BytecodeGenerator.CLASS_NAME)) {
						Class<?> clazz = defineClass(BytecodeGenerator.CLASS_NAME, bytecode, 0, bytecode.length);
						resolveClass(clazz);
						return clazz;
					}
					return super.findClass(name);
				}
			};
			
			loader.loadClass(BytecodeGenerator.CLASS_NAME)
			      .getMethod("main", args.getClass())
			      .invoke(null, new Object[] {args});
			
			
		} catch (LexerException le) {
			Utils.reportSyntaxError(le, file.getName());
		} catch (ParserException pe) {
			Utils.reportSyntaxError(pe, file.getName());
		} catch (SemanticException se) {
			// skip...
		}
	}
}
